home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Joystick Magazine 1996 May
/
cd joy 71No13.iso
/
pc
/
demos
/
waynegre
/
model.mac
< prev
next >
Wrap
Text File
|
1994-08-22
|
14KB
|
483 lines
;****************************************************************************
;*
;* Copyright (C) 1994 SciTech Software.
;* All rights reserved.
;*
;* Filename: $RCSfile: model.mac $
;* Version: $Revision: 1.5 $
;*
;* Language: Turbo Assembler 3.0
;* Environment: IBM PC (MS DOS)
;*
;* Description: Macros to provide memory model independant assembly language
;* module for C programming. Supports the large memory model
;* and 386 extended DOS memory models.
;*
;* The defines that you should use when assembling modules that
;* use this macro package are:
;*
;* __LARGE__ Assemble for real mode large memory model
;* __X386__ Assemble for 386 extended memory model
;* __FLAT__ Assemble for 386 FLAT memory model
;* __8086__ Assemble for 8086 real mode code
;* __80286__ Assemble for 80286 real mode code
;* __COMM__ Declare global variables as COMMunal
;*
;* By default the real mode large memory model targeted for the
;* 80386 processor is selected.
;*
;* Note that we use the TASM simplified segment directives so
;* that 32 bit code will assemble correctly, and we also use
;* TASM's IDEAL mode syntax, so this is not compatible with
;* MASM. The __FLAT__ mode should be used whenever possible to
;* assemble code that needs to be converted to Unix style .o
;* files for DJGPP and EMX, and for most new compilers. Symantec
;* C++ however requires the __X386__ memory model, or it will not
;* link correctly). You should specify either of __X386__ or
;* __FLAT__ to assemble code correctly.
;*
;* The main intent of the macro file is to enable programmers
;* to write _one_ set of source that can be assembled to run
;* in either 16 bit real and protected modes or 32 bit
;* protected mode without the need to riddle the code with
;* 'if flatmodel' style conditional assembly (it is still there
;* but nicely hidden by a macro layer that enhances the
;* readability and understandability of the resulting code).
;*
;* NOTES: When you declare the data and code segments, you should specify
;* a name to be used. This name should be the name of the file
;* being assembled, but you may use the same name for mutiple
;* modules if you wish so that the data and code for these modules
;* are all contained in the same segments. Of course the maximum
;* size of data and code must be less than 64k respectively.
;*
;* $Id: model.mac 1.5 1994/08/22 07:58:32 kjb release $
;*
;****************************************************************************
IDEAL
; Define symbols codesize and datasize depending on the requested memory
; model. Note that because of the differences in addressing used in the
; 16 and 32 bit memory models, we need a couple of macros to define things
; such as what register is used for looping (CX or ECX) etc. Note that we
; can use simple 16 bit code in 32 bit mode and vice-versa, but unless this
; is absolutely necessary it poses the performance hit of requiring an
; operand size prefex for the instruction. Hence if we simply need to use
; a set of registers for an operation, use the macros to use the best
; register for the current mode of operation. Of course the real registers
; may be specified for operations that specifically require 16 or 32 bits.
;
; The following things are defined:
;
; UCHAR - Typedef for a character type
; USHORT - Typedef for a short type
; UINT - Typedef for an integer type
; BOOL - Typedef for a boolean type
; DPTR - Operand size of data pointers
; DDIST - Distance to data variables (NEAR or FAR)
; CPTR - Operand size of code pointers
; FCPTR - Operand size of far code pointers
; NCPTR - Operand size of near code pointers
; FPTR - Function pointer modifier, either NEAR or FAR
; _AX - General accumulator register, either AX or EAX
; _BX - General base register, either BX or EBX
; _CX - Loop counter register, either CX or ECX
; CXPTR - Operand size of loop counter, either WORD or DWORD
; _DX - General data register, either DX or EDX
; _SI - Source index register, either SI or ESI
; _DI - Destination index register, either DI or EDI
; _BP - Base pointer register, either BP or EBP
; _SP - Stack pointer register, either SP or ESP
; _ES - ES segment override - evaluates to nothing in 32 bit PM
ifdef __FLAT__
__X386__ = 1
endif
ifdef __X386__
flatmodel EQU 1 ; This is a flat memory model
datasize EQU 0 ; Near data memory model
dptrsize EQU 4 ; Size of a data pointer (32 bit near)
stackalign EQU 4 ; Align stack to 4 byte boundary
typedef UCHAR BYTE ; Size of a character
typedef USHORT WORD ; Size of a short
typedef UINT DWORD ; Size of an integer
typedef ULONG DWORD ; Size of a long
typedef BOOL WORD ; Size of a boolean
typedef DPTR DWORD ; Size of a data pointer
typedef FDPTR FWORD ; Size of a far data pointer
typedef NDPTR DWORD ; Size of a near data pointer
DDIST EQU NEAR
codesize EQU 0 ; Near code memory model
cptrsize EQU 4
typedef CPTR DWORD ; Size of a code pointer
typedef FCPTR FWORD ; Size of a far code pointer
typedef NCPTR DWORD ; Size of a near code pointer
FPTR EQU NEAR
_AX EQU EAX ; EAX is used for accumulator
_BX EQU EBX ; EBX is used for accumulator
_CX EQU ECX ; ECX is used for looping
CXPTR EQU DWORD ; loop variables are 32 bits
_DX EQU EDX ; EDX is used for data register
_SI EQU ESI ; ESI is the source index register
_DI EQU EDI ; EDI is the destination index register
_BP EQU EBP ; EBP is used for base pointer register
_SP EQU ESP ; ESP is used for stack pointer register
_ES EQU ; ES and DS are the same in 32 bit PM
P386 ; Turn on 386 code generation
ifdef __FLAT__
MODEL FLAT ; Set up for 32 bit simplified FLAT model
else
LARGESTACK ; Set up for a 32 bit stack model
endif
else
flatmodel EQU 0 ; This is a segmented memory model
datasize EQU 1 ; Far data memory model
dptrsize EQU 4 ; Size of a data pointer
stackalign EQU 2 ; Align stack to 2 byte boundary
typedef UCHAR BYTE ; Size of a character
typedef USHORT WORD ; Size of a short
typedef UINT WORD ; Size of an integer
typedef ULONG DWORD ; Size of a long
typedef BOOL WORD ; Size of a boolean
typedef DPTR DWORD ; Size of a data pointer
typedef FDPTR DWORD ; Size of a far data pointer
typedef NDPTR WORD ; Size of a near data pointer
DDIST EQU FAR
codesize EQU 1 ; Far code memory model
cptrsize EQU 4 ; Size of a code pointer
typedef CPTR DWORD ; Size of a code pointer
typedef FCPTR DWORD ; Size of a far code pointer
typedef NCPTR WORD ; Size of a near code pointer
FPTR EQU FAR
_AX EQU AX ; AX is used for accumulator
_BX EQU BX ; BX is used for accumulator
_CX EQU CX ; CX is used for looping
CXPTR EQU WORD ; loop variables are 16 bits
_DX EQU DX ; DX is used for data register
_SI EQU SI ; SI is the source index register
_DI EQU DI ; DI is the destination index register
_BP EQU BP ; BP is used for base pointer register
_SP EQU SP ; SP is used for stack pointer register
_ES EQU es: ; ES is used for segment override
ifndef __8086__
ifdef __80286__
P286 ; Turn on 286 code generation
else
P386 ; Turn on 386 code generation
endif
endif
endif
; Macros for declaring external global variables
ifdef __COMM__
MACRO $EXTRN name,type
COMM DDIST name:type
ENDM
else
MACRO $EXTRN name,type
EXTRN name:type
ENDM
endif
; Macros for entering and exiting C callable functions. Note that we must
; always save and restore the SI and DI registers for C functions, and for
; 32 bit C functions we also need to save and restore EBX and clear the
; direction flag.
MACRO enter_c LocalSize
ifdef __8086__
push bp
mov bp,sp
sub sp,LocalSize
else
enter LocalSize,0
ifdef __X386__
push ebx
endif
endif
push _si
push _di
ENDM
MACRO leave_c
pop _di
pop _si
ifdef __X386__
pop ebx
endif
cld
ifdef __8086__
mov sp,bp
pop bp
else
leave
endif
ENDM
MACRO use_ebx
if flatmodel
push ebx
endif
ENDM
MACRO unuse_ebx
if flatmodel
pop ebx
endif
ENDM
; Macros for saving and restoring the value of DS,ES,FS,GS when it is to
; be used in assembly routines. This evaluates to nothing in the flat memory
; model, but is saves and restores DS in the normal memory model.
MACRO use_ds
ife flatmodel
push ds
endif
ENDM
MACRO unuse_ds
ife flatmodel
pop ds
endif
ENDM
MACRO use_es
ife flatmodel
push es
endif
ENDM
MACRO unuse_es
ife flatmodel
pop es
endif
ENDM
; Macros for loading the address of a data pointer into a segment and
; index register pair. The macro explicitly loads DS or ES in the 16 bit
; memory model, or it simply loads the offset into the register in the flat
; memory model since DS and ES always point to all addressable memory. You
; must use the correct _REG (ie: _BX) macros for documentation purposes.
MACRO _lds reg, addr
if flatmodel
mov reg,addr
else
lds reg,addr
endif
ENDM
MACRO _les reg, addr
if flatmodel
mov reg,addr
else
les reg,addr
endif
ENDM
; Macros for setting the value of the DS,ES,FS,GS registers to the same
; value. This is does nothing in 32 bit protected mode.
MACRO es_eq_ds
ife flatmodel
push ds
pop es
endif
ENDM
MACRO ds_eq_es
ife flatmodel
push es
pop ds
endif
ENDM
MACRO fs_eq_ds
ife flatmodel
push ds
pop fs
endif
ENDM
; Macro for loading a value into a register given a pointer and an
; offset from the pointer. Will work in either 16 and 32 bit mode.
;
; NOTE: The value of BX or EBX will be trashed over this macro!!
MACRO get_val reg, pointer, offset
if flatmodel
mov ebx,[pointer]
mov reg,[ebx + offset]
else
les bx,[pointer]
mov reg,[es:bx + offset]
endif
ENDM
; Macros for adding and subtracting a value from registers. Two value are
; provided, one for 16 bit modes and another for 32 bit modes (the extended
; register is used in 32 bit modes).
MACRO _add reg, val16, val32
if flatmodel
add e®&, val32
else
add reg, val16
endif
ENDM
MACRO _sub reg, val16, val32
if flatmodel
sub e®&, val32
else
sub reg, val16
endif
ENDM
; Macro to clear the high order word for the 32 bit extended registers.
; This is used to convert an unsigned 16 bit value to an unsigned 32 bit
; value, and will evaluate to nothing in 16 bit modes.
MACRO clrhi reg
if flatmodel
and reg, 0FFFFh ; Mask out top 16 bit
endif
ENDM
; Macro to load an extended register with an integer value in either mode
MACRO loadint reg,val
if flatmodel
mov e®&,val
else
xor e®&,e®&
mov reg,val
endif
ENDM
; Macros for procedure definitions given a name. Note that they also export
; the symbol with the PUBLIC directive, so that it need not be explicitly
; exported.
MACRO procstart name ; Set up model independant proc
if codesize ; and export name
PROC name FAR
else
PROC name NEAR
endif
PUBLIC name
ENDM
MACRO procstatic name ; Set up model independant private proc
if codesize
PROC name FAR
else
PROC name NEAR
endif
ENDM
MACRO procnear name ; Set up near proc
PROC name NEAR ; and export name
PUBLIC name
ENDM
MACRO procfar name ; Set up far proc
PROC name FAR ; and export name
PUBLIC name
ENDM
MACRO procend name ; End procedure macro
ENDP name
ENDM
; Macros for the _DATA data segment. This segment contains initialised data.
MACRO begdataseg name
ifdef __FLAT__
DATASEG
else
if flatmodel
SEGMENT _DATA DWORD PUBLIC USE32 'DATA'
else
SEGMENT _DATA WORD PUBLIC 'DATA'
endif
endif
ENDM
MACRO enddataseg name
ifndef __FLAT__
ENDS _DATA
endif
ENDM
; Macros for the _BSS data segment. This segment contains initialised data.
MACRO begbssseg name
ifdef __FLAT__
DATASEG
else
if flatmodel
SEGMENT _BSS DWORD PUBLIC USE32 'BSS'
else
SEGMENT _BSS WORD PUBLIC 'BSS'
endif
endif
ENDM
MACRO endbssseg name
ifndef __FLAT__
ENDS _BSS
endif
ENDM
; Macro to be invoked at the start of all modules to set up segments for
; later use.
MACRO header name
begdataseg name
enddataseg name
begbssseg name
endbssseg name
ENDM
; Macro for the main code segment.
MACRO begcodeseg name
ifdef __FLAT__
CODESEG
ASSUME CS:FLAT,DS:FLAT
else
if flatmodel
SEGMENT _TEXT DWORD PUBLIC USE32 'CODE'
GROUP DGROUP _DATA,_BSS
ASSUME CS:_TEXT,DS:DGROUP
else
SEGMENT &name&_TEXT BYTE PUBLIC 'CODE'
GROUP DGROUP _DATA,_BSS
ASSUME CS:&name&_TEXT,DS:DGROUP
endif
endif
ENDM
MACRO endcodeseg name
ifndef __FLAT__
if flatmodel
ENDS _TEXT
else
ENDS &name&_TEXT
endif
endif
ENDM
; Boolean truth values (same as those in debug.h)
False = 0
True = 1
No = 0
Yes = 1